package com.zmj.framework.base.controller;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zmj.framework.base.entity.IEntity;
import com.zmj.framework.base.service.IBaseService;
import com.zmj.framework.base.sql.Condition;
import com.zmj.framework.base.sql.Query;
import com.zmj.framework.base.vo.BatchId;
import com.zmj.framework.exception.server.ServerException;
import com.zmj.framework.response.Result;
import com.zmj.framework.util.ThreadContextHandler;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.lang.reflect.ParameterizedType;
import java.util.Map;

/**
 * @author scy
 * controller 基础类 提供基础的增删改查
 */
public class BaseController<S extends IBaseService<Entity>, Entity extends IEntity> {
    @Autowired
    public S baseService;

    private boolean checkRepeat(Entity entity) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

        //获取请求地址
        String requestUri = request.getRequestURI();
        //获取用户ID
        String username = ThreadContextHandler.getCurrentUser().getUsername();
        //拼接锁前缀，采用同一方法，同一用户,同一接口
        String key = requestUri.concat(entity.toString()) + (username != null ? username : "");
        key = key.replaceAll("/", "");

        boolean repeat = baseService.getRepeatLock(key);
        if (!repeat) {
            baseService.setRepeatLock(key);
        }
        return repeat;
    }

    @RateLimiter(name = "simple")
    @ApiOperation(value = "添加")
    @PostMapping(value = "add")
    @ResponseBody
    public Result<Entity> add(@Valid @RequestBody Entity entity) {
        if (checkRepeat(entity)) {
            return Result.fail("您当前的操作太频繁了,请稍后再试！");
        }
        boolean t = baseService.save(entity);
        return Result.success(entity);
    }

    @RateLimiter(name = "simple")
    @ApiOperation(value = "根据id修改")
    @PutMapping(value = "update")
    @ResponseBody
    public Result<Entity> update(@Valid @RequestBody Entity entity) {
        boolean t = baseService.updateById(entity);
        if (!t) {
            throw new ServerException("修改失败！");
        }
        return Result.success(entity);
    }

    @RateLimiter(name = "simple")
    @ApiOperation(value = "根据id查询详情")
    @GetMapping(value = "get/{id}")
    @ResponseBody
    public Result<Entity> get(@PathVariable String id) {
        Assert.notBlank(id, "id不能为空！");
        Entity tenant = baseService.getById(id);
        return Result.success(tenant);
    }

    @RateLimiter(name = "simple")
    @ApiOperation(value = "批量删除")
    @DeleteMapping(value = "delete")
    @ResponseBody
    public Result<Entity> deleteBatch(@Valid @RequestBody BatchId batchId) {
        boolean t = baseService.removeBatchByIds(batchId.getIds());
        if (!t) {
            throw new ServerException("删除失败！");
        }
        return Result.success();
    }

    @RateLimiter(name = "simple")
    @ApiOperation(value = "分页查询", notes = "\n1、分页查询支持按照指定字段排序和自定义排序方式：\n" +
            "  需传递：order、orderBy两个参数，orderBy为对象属性。\n" +
            "2、分页查询支持自定义查询条件：\n" +
            "  查询条件中拼接所需要的的查询对象属性+条件类型即可，如查询条件username='amdin'，则在查询条件中增加username_equal=admin。如果查询对象属性不跟条件类型则系统默认为like方式。\n" +
            "实例：\n" +
            "curl --location --request GET 'http://localhost:9002/user/page?<b>current=1&order=ASC&orderBy=createTime&size=10&tenantId=default-tenan&jobNumber_equal=184488&createTime_gt=1591066023816</b>'\n" +
            "支持的条件类型如下表：\n" +
            "<table style=\"width:40%\"><colgroup><col /><col /><col /></colgroup><tbody><tr><td>类型</td><td>说明</td><td>等价于</td></tr><tr><td><span >_equal</span></td><td>等于</td><td>=</td></tr><tr><td><span >_notequal</span></td><td>不等于</td><td>!=</td></tr><tr><td><span >_like</span></td><td>模糊查询</td><td>like %x%</td></tr><tr><td><span >_notlike</span></td><td>模糊不匹配查询</td><td>not like %x%</td></tr><tr><td><span >_gt</span></td><td>大于</td><td>&gt;</td></tr><tr><td><span >_lt</span></td><td>小于</td><td>&lt;</td></tr><tr><td><span >_dategt</span></td><td>大于</td><td>&gt;</td></tr><tr><td><span >_dateequal</span></td><td>等于</td><td>=</td></tr><tr><td><span >_datelt</span></td><td>小于</td><td>&lt;</td></tr><tr><td><span >_null</span></td><td>空</td><td>is null</td></tr><tr><td><span >_notnull</span></td><td>非空</td><td>is not null</td></tr><tr><td><span >_ignore</span></td><td>放弃</td><td>条件不生效</td></tr></tbody></table>")
    @GetMapping(value = "page")
    @ResponseBody
    public Result<IPage<Entity>> page(@ApiIgnore @RequestParam Map<String, Object> param, Query query) {
        Class<Entity> entityClass = (Class<Entity>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        IPage<Entity> pages = baseService.page(Condition.getPage(query), Condition.getQueryWrapper(param, entityClass));
        return Result.success(pages);
    }
}
